package prototypes;

import java.util.NoSuchElementException;
import java.util.Scanner;

/**
 * An Operations Protocol packet.
 * 
 * @author Matthew Johnstone <mjohnstone357@gmail.com>
 * 
 */
public class Packet {

	public static final String PACKET_HEADER = "OPERATIONS_PACKET";

	private String sourceNodeName;
	private String destinationNodeName;

	private String sourceServiceName;
	private String destinationServiceName;

	private String lastHopSignature;
	private String sourceSignature;

	private String payload;

	/**
	 * Constructor that parses the provided text to produce an Operations
	 * Protocol packet.
	 * 
	 * @param text
	 *            the packet in text form, as generated by the toText method.
	 * @throws PacketParsingException
	 *             if the text does not represent a valid packet.
	 */
	public Packet(String text) throws PacketParsingException {
		
		Scanner scanner = new Scanner(text);
		
		try{
			
			String header = scanner.nextLine();
			
			if (!header.equals(PACKET_HEADER)){
				throw new PacketParsingException();
			}
			
			sourceNodeName = scanner.nextLine();
			destinationNodeName = scanner.nextLine();
			sourceServiceName = scanner.nextLine();
			destinationServiceName = scanner.nextLine();
			lastHopSignature = scanner.nextLine();
			sourceSignature = scanner.nextLine();
		}
		catch (NoSuchElementException e){
			throw new PacketParsingException();
		}
		

	}

	/**
	 * Overridden toString method. This produces a String showing the contents
	 * of the packet in a human-readable form.
	 * 
	 * Note: this is not the text that is sent across the network- use the
	 * {@link prototypes.Packet#toText toText()} method for that.
	 * 
	 */
	@Override
	public String toString() {

		String line = "==============================\n";

		String wrappedHopSignature = Utilities.wrap(line.length() - 1, lastHopSignature);
		String wrappedSourceSignature = Utilities.wrap(line.length() - 1, sourceSignature);

		return line + "Operations Protocol Packet:\n" + line + "Source:\t\t"
					+ sourceNodeName + "::" + sourceServiceName + "\n"
				+ "Destination:\t" + destinationNodeName + "::"
					+ destinationServiceName + "\n" +
				"Last-hop Signature:\t" + wrappedHopSignature +
				"Source Signature:\t" + wrappedSourceSignature +
				line;

	}

	/**
	 * Method to produce a textual version of the Packet that is suitable for
	 * transmission between Operations Server instances.
	 * 
	 * @return a String representing the Packet that can be transmitted between
	 *         Operations Server instances.
	 */
	public String toText() {

		return PACKET_HEADER + "\n" + sourceNodeName + "\n"
				+ destinationNodeName + "\n" + sourceServiceName + "\n"
				+ destinationServiceName + "\n" + lastHopSignature + "\n"
				+ sourceSignature + "\n";
	}
	
	public String getLastHopSignature() {
		return lastHopSignature;
	}

	public void setLastHopSignature(String lastHopSignature) {
		this.lastHopSignature = lastHopSignature;
	}

	public static String getPacketHeader() {
		return PACKET_HEADER;
	}

	public String getSourceNodeName() {
		return sourceNodeName;
	}

	public String getDestinationNodeName() {
		return destinationNodeName;
	}

	public String getSourceServiceName() {
		return sourceServiceName;
	}

	public String getDestinationServiceName() {
		return destinationServiceName;
	}

	public String getSourceSignature() {
		return sourceSignature;
	}

	public String getPayload() {
		return payload;
	}

	@Override
	public boolean equals(Object o){
		
		if (o == null) return false;
		
		if (o.getClass() != this.getClass()) return false;
		
		Packet p = (Packet) o;
		
		return p.destinationNodeName.equals(destinationNodeName) &&
				p.destinationServiceName.equals(destinationServiceName) &&
				p.sourceNodeName.equals(sourceNodeName) &&
				p.sourceServiceName.equals(sourceServiceName) &&
				p.lastHopSignature.equals(lastHopSignature) &&
				p.sourceSignature.equals(sourceSignature) &&
				p.payload.equals(payload);
		
	}

	@Override
	public int hashCode(){
		
		int h = 13 + ((sourceNodeName==null) ? 0 : sourceNodeName.hashCode());
		
		h = h * 17 + ((destinationNodeName==null) ? 0 : destinationNodeName.hashCode());
		h = h * 19 + ((sourceServiceName==null) ? 0 : sourceServiceName.hashCode());
		h = h * 23 + ((destinationServiceName==null) ? 0 : destinationServiceName.hashCode());
		h = h * 29 + ((lastHopSignature==null) ? 0 : lastHopSignature.hashCode());
		h = h * 31 + ((sourceSignature==null) ? 0 : sourceSignature.hashCode());
		h = h * 37 + ((payload==null) ? 0 : payload.hashCode());
		
		return h;
		
	}


}
